{
 "cells": [
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:26:12.796257Z",
     "start_time": "2025-01-26T07:26:08.552939Z"
    }
   },
   "source": [
    "import matplotlib as mpl\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "import numpy as np\n",
    "import sklearn\n",
    "import pandas as pd\n",
    "import os\n",
    "import sys\n",
    "import time\n",
    "from tqdm.auto import tqdm\n",
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "\n",
    "print(sys.version_info)\n",
    "for module in mpl, np, pd, sklearn, torch:\n",
    "    print(module.__name__, module.__version__)\n",
    "    \n",
    "device = torch.device(\"cuda:0\") if torch.cuda.is_available() else torch.device(\"cpu\")\n",
    "print(device)\n"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sys.version_info(major=3, minor=12, micro=3, releaselevel='final', serial=0)\n",
      "matplotlib 3.10.0\n",
      "numpy 1.26.4\n",
      "pandas 2.2.3\n",
      "sklearn 1.6.1\n",
      "torch 2.5.1+cpu\n",
      "cpu\n"
     ]
    }
   ],
   "execution_count": 1
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 加载数据"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:26:14.620889Z",
     "start_time": "2025-01-26T07:26:12.797256Z"
    }
   },
   "source": [
    "from torchvision import datasets\n",
    "from torchvision.transforms import ToTensor\n",
    "\n",
    "# fashion_mnist图像分类数据集\n",
    "train_ds = datasets.FashionMNIST(\n",
    "    root=\"data\",\n",
    "    train=True,\n",
    "    download=True,\n",
    "    transform=ToTensor()\n",
    ")\n",
    "\n",
    "test_ds = datasets.FashionMNIST(\n",
    "    root=\"data\",\n",
    "    train=False,\n",
    "    download=True,\n",
    "    transform=ToTensor()\n",
    ")\n",
    "\n",
    "# torchvision 数据集里没有提供训练集和验证集的划分\n",
    "# 当然也可以用 torch.utils.data.Dataset 实现人为划分\n",
    "# 从数据集到dataloader\n",
    "train_loader = torch.utils.data.DataLoader(train_ds, batch_size=16, shuffle=True)\n",
    "val_loader = torch.utils.data.DataLoader(test_ds, batch_size=16, shuffle=False)"
   ],
   "outputs": [],
   "execution_count": 2
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:26:14.627153Z",
     "start_time": "2025-01-26T07:26:14.621990Z"
    }
   },
   "source": [
    "from torchvision.transforms import Normalize\n",
    "\n",
    "# 遍历train_ds得到每张图片，计算每个通道的均值和方差\n",
    "def cal_mean_std(ds):\n",
    "    mean = 0.\n",
    "    std = 0.\n",
    "    for img, _ in ds:\n",
    "        mean += img.mean(dim=(1, 2))\n",
    "        std += img.std(dim=(1, 2))\n",
    "    mean /= len(ds)\n",
    "    std /= len(ds)\n",
    "    return mean, std\n",
    "\n",
    "\n",
    "# print(cal_mean_std(train_ds))\n",
    "# 0.2860， 0.3205\n",
    "transforms = nn.Sequential(\n",
    "    Normalize([0.2860], [0.3205])\n",
    ")\n"
   ],
   "outputs": [],
   "execution_count": 3
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 定义模型\n",
    "\n",
    "这里我们没有用`nn.Linear`的默认初始化，而是采用了xavier均匀分布去初始化全连接层的权重\n",
    "\n",
    "xavier初始化出自论文 《Understanding the difficulty of training deep feedforward neural networks》，适用于使用`tanh`和`sigmoid`激活函数的方法。当然，我们这里的模型采用的是`relu`激活函数，采用He初始化（何凯明初始化）会更加合适。感兴趣的同学可以自己动手修改并比对效果。\n",
    "\n",
    "|神经网络层数|初始化方式|early stop at epoch| val_loss | vla_acc|\n",
    "|-|-|-|-|-|\n",
    "|20|默认|\n",
    "|20|xaviier_uniform|\n",
    "|20|he_uniform|\n",
    "|...|\n",
    "\n",
    "He初始化出自论文 《Delving deep into rectifiers: Surpassing human-level performance on ImageNet classification》"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:26:14.664836Z",
     "start_time": "2025-01-26T07:26:14.627153Z"
    }
   },
   "source": [
    "class NeuralNetwork(nn.Module):\n",
    "    def __init__(self, layers_num=2):\n",
    "        super().__init__()\n",
    "        self.transforms = transforms\n",
    "        self.flatten = nn.Flatten()\n",
    "        # 多加几层\n",
    "        self.linear_relu_stack = nn.Sequential(\n",
    "            nn.Linear(28 * 28, 100),  # in_features=784, out_features=300\n",
    "            # 一般而言，先batch norm 后 激活函数\n",
    "            # 参见论文 《Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift》\n",
    "            nn.BatchNorm1d(100),  # num of features=100\n",
    "            nn.ReLU(),\n",
    "        )\n",
    "        # 加19层\n",
    "        for i in range(1, layers_num):\n",
    "            self.linear_relu_stack.add_module(f\"Linear_{i}\", nn.Linear(100, 100))\n",
    "            self.linear_relu_stack.add_module(f\"batchnorm_{i}\", nn.BatchNorm1d(100))  # 批归一化\n",
    "            self.linear_relu_stack.add_module(f\"relu\", nn.ReLU())\n",
    "        # 输出层\n",
    "        self.linear_relu_stack.add_module(\"Output Layer\", nn.Linear(100, 10))\n",
    "        \n",
    "        self.init_weights()\n",
    "        \n",
    "    def init_weights(self):\n",
    "        \"\"\"使用 xavier 均匀分布来初始化全连接层的权重 W\"\"\"\n",
    "        for m in self.modules():\n",
    "            if isinstance(m, nn.Linear):\n",
    "                nn.init.xavier_uniform_(m.weight)\n",
    "                nn.init.zeros_(m.bias)\n",
    "\n",
    "    def forward(self, x):\n",
    "        # x.shape [batch size, 1, 28, 28]\n",
    "        x = self.transforms(x)\n",
    "        x = self.flatten(x)  \n",
    "        # 展平后 x.shape [batch size, 28 * 28]\n",
    "        logits = self.linear_relu_stack(x)\n",
    "        # logits.shape [batch size, 10]\n",
    "        return logits\n",
    "\n",
    "print(f\"{'layer_name':^40}\\tparamerters num\")\n",
    "total_params = 0\n",
    "for idx, (key, value) in enumerate(NeuralNetwork(20).named_parameters()):\n",
    "    print(\"{}{:<40}\\t{:^10}\".format(idx,key, np.prod(value.shape)))\n",
    "    total_params += np.prod(value.shape)\n",
    "total_params"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "               layer_name               \tparamerters num\n",
      "0linear_relu_stack.0.weight              \t  78400   \n",
      "1linear_relu_stack.0.bias                \t   100    \n",
      "2linear_relu_stack.1.weight              \t   100    \n",
      "3linear_relu_stack.1.bias                \t   100    \n",
      "4linear_relu_stack.Linear_1.weight       \t  10000   \n",
      "5linear_relu_stack.Linear_1.bias         \t   100    \n",
      "6linear_relu_stack.batchnorm_1.weight    \t   100    \n",
      "7linear_relu_stack.batchnorm_1.bias      \t   100    \n",
      "8linear_relu_stack.Linear_2.weight       \t  10000   \n",
      "9linear_relu_stack.Linear_2.bias         \t   100    \n",
      "10linear_relu_stack.batchnorm_2.weight    \t   100    \n",
      "11linear_relu_stack.batchnorm_2.bias      \t   100    \n",
      "12linear_relu_stack.Linear_3.weight       \t  10000   \n",
      "13linear_relu_stack.Linear_3.bias         \t   100    \n",
      "14linear_relu_stack.batchnorm_3.weight    \t   100    \n",
      "15linear_relu_stack.batchnorm_3.bias      \t   100    \n",
      "16linear_relu_stack.Linear_4.weight       \t  10000   \n",
      "17linear_relu_stack.Linear_4.bias         \t   100    \n",
      "18linear_relu_stack.batchnorm_4.weight    \t   100    \n",
      "19linear_relu_stack.batchnorm_4.bias      \t   100    \n",
      "20linear_relu_stack.Linear_5.weight       \t  10000   \n",
      "21linear_relu_stack.Linear_5.bias         \t   100    \n",
      "22linear_relu_stack.batchnorm_5.weight    \t   100    \n",
      "23linear_relu_stack.batchnorm_5.bias      \t   100    \n",
      "24linear_relu_stack.Linear_6.weight       \t  10000   \n",
      "25linear_relu_stack.Linear_6.bias         \t   100    \n",
      "26linear_relu_stack.batchnorm_6.weight    \t   100    \n",
      "27linear_relu_stack.batchnorm_6.bias      \t   100    \n",
      "28linear_relu_stack.Linear_7.weight       \t  10000   \n",
      "29linear_relu_stack.Linear_7.bias         \t   100    \n",
      "30linear_relu_stack.batchnorm_7.weight    \t   100    \n",
      "31linear_relu_stack.batchnorm_7.bias      \t   100    \n",
      "32linear_relu_stack.Linear_8.weight       \t  10000   \n",
      "33linear_relu_stack.Linear_8.bias         \t   100    \n",
      "34linear_relu_stack.batchnorm_8.weight    \t   100    \n",
      "35linear_relu_stack.batchnorm_8.bias      \t   100    \n",
      "36linear_relu_stack.Linear_9.weight       \t  10000   \n",
      "37linear_relu_stack.Linear_9.bias         \t   100    \n",
      "38linear_relu_stack.batchnorm_9.weight    \t   100    \n",
      "39linear_relu_stack.batchnorm_9.bias      \t   100    \n",
      "40linear_relu_stack.Linear_10.weight      \t  10000   \n",
      "41linear_relu_stack.Linear_10.bias        \t   100    \n",
      "42linear_relu_stack.batchnorm_10.weight   \t   100    \n",
      "43linear_relu_stack.batchnorm_10.bias     \t   100    \n",
      "44linear_relu_stack.Linear_11.weight      \t  10000   \n",
      "45linear_relu_stack.Linear_11.bias        \t   100    \n",
      "46linear_relu_stack.batchnorm_11.weight   \t   100    \n",
      "47linear_relu_stack.batchnorm_11.bias     \t   100    \n",
      "48linear_relu_stack.Linear_12.weight      \t  10000   \n",
      "49linear_relu_stack.Linear_12.bias        \t   100    \n",
      "50linear_relu_stack.batchnorm_12.weight   \t   100    \n",
      "51linear_relu_stack.batchnorm_12.bias     \t   100    \n",
      "52linear_relu_stack.Linear_13.weight      \t  10000   \n",
      "53linear_relu_stack.Linear_13.bias        \t   100    \n",
      "54linear_relu_stack.batchnorm_13.weight   \t   100    \n",
      "55linear_relu_stack.batchnorm_13.bias     \t   100    \n",
      "56linear_relu_stack.Linear_14.weight      \t  10000   \n",
      "57linear_relu_stack.Linear_14.bias        \t   100    \n",
      "58linear_relu_stack.batchnorm_14.weight   \t   100    \n",
      "59linear_relu_stack.batchnorm_14.bias     \t   100    \n",
      "60linear_relu_stack.Linear_15.weight      \t  10000   \n",
      "61linear_relu_stack.Linear_15.bias        \t   100    \n",
      "62linear_relu_stack.batchnorm_15.weight   \t   100    \n",
      "63linear_relu_stack.batchnorm_15.bias     \t   100    \n",
      "64linear_relu_stack.Linear_16.weight      \t  10000   \n",
      "65linear_relu_stack.Linear_16.bias        \t   100    \n",
      "66linear_relu_stack.batchnorm_16.weight   \t   100    \n",
      "67linear_relu_stack.batchnorm_16.bias     \t   100    \n",
      "68linear_relu_stack.Linear_17.weight      \t  10000   \n",
      "69linear_relu_stack.Linear_17.bias        \t   100    \n",
      "70linear_relu_stack.batchnorm_17.weight   \t   100    \n",
      "71linear_relu_stack.batchnorm_17.bias     \t   100    \n",
      "72linear_relu_stack.Linear_18.weight      \t  10000   \n",
      "73linear_relu_stack.Linear_18.bias        \t   100    \n",
      "74linear_relu_stack.batchnorm_18.weight   \t   100    \n",
      "75linear_relu_stack.batchnorm_18.bias     \t   100    \n",
      "76linear_relu_stack.Linear_19.weight      \t  10000   \n",
      "77linear_relu_stack.Linear_19.bias        \t   100    \n",
      "78linear_relu_stack.batchnorm_19.weight   \t   100    \n",
      "79linear_relu_stack.batchnorm_19.bias     \t   100    \n",
      "80linear_relu_stack.Output Layer.weight   \t   1000   \n",
      "81linear_relu_stack.Output Layer.bias     \t    10    \n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "275410"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "execution_count": 4
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 训练"
   ]
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:26:14.723046Z",
     "start_time": "2025-01-26T07:26:14.665836Z"
    }
   },
   "source": [
    "from sklearn.metrics import accuracy_score\n",
    "\n",
    "@torch.no_grad()\n",
    "def evaluating(model, dataloader, loss_fct):\n",
    "    loss_list = []\n",
    "    pred_list = []\n",
    "    label_list = []\n",
    "    for datas, labels in dataloader:\n",
    "        datas = datas.to(device)\n",
    "        labels = labels.to(device)\n",
    "        # 前向计算\n",
    "        logits = model(datas)\n",
    "        loss = loss_fct(logits, labels)         # 验证集损失\n",
    "        loss_list.append(loss.item())\n",
    "        \n",
    "        preds = logits.argmax(axis=-1)    # 验证集预测\n",
    "        pred_list.extend(preds.cpu().numpy().tolist())\n",
    "        label_list.extend(labels.cpu().numpy().tolist())\n",
    "        \n",
    "    acc = accuracy_score(label_list, pred_list)\n",
    "    return np.mean(loss_list), acc\n"
   ],
   "outputs": [],
   "execution_count": 5
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:26:18.124433Z",
     "start_time": "2025-01-26T07:26:14.724034Z"
    }
   },
   "source": [
    "from torch.utils.tensorboard import SummaryWriter\n",
    "\n",
    "\n",
    "class TensorBoardCallback:\n",
    "    def __init__(self, log_dir, flush_secs=10):\n",
    "        \"\"\"\n",
    "        Args:\n",
    "            log_dir (str): dir to write log.\n",
    "            flush_secs (int, optional): write to dsk each flush_secs seconds. Defaults to 10.\n",
    "        \"\"\"\n",
    "        self.writer = SummaryWriter(log_dir=log_dir, flush_secs=flush_secs)\n",
    "\n",
    "    def draw_model(self, model, input_shape):\n",
    "        self.writer.add_graph(model, input_to_model=torch.randn(input_shape))\n",
    "        \n",
    "    def add_loss_scalars(self, step, loss, val_loss):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/loss\", \n",
    "            tag_scalar_dict={\"loss\": loss, \"val_loss\": val_loss},\n",
    "            global_step=step,\n",
    "            )\n",
    "        \n",
    "    def add_acc_scalars(self, step, acc, val_acc):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/accuracy\",\n",
    "            tag_scalar_dict={\"accuracy\": acc, \"val_accuracy\": val_acc},\n",
    "            global_step=step,\n",
    "        )\n",
    "        \n",
    "    def add_lr_scalars(self, step, learning_rate):\n",
    "        self.writer.add_scalars(\n",
    "            main_tag=\"training/learning_rate\",\n",
    "            tag_scalar_dict={\"learning_rate\": learning_rate},\n",
    "            global_step=step,\n",
    "            \n",
    "        )\n",
    "    \n",
    "    def __call__(self, step, **kwargs):\n",
    "        # add loss\n",
    "        loss = kwargs.pop(\"loss\", None)\n",
    "        val_loss = kwargs.pop(\"val_loss\", None)\n",
    "        if loss is not None and val_loss is not None:\n",
    "            self.add_loss_scalars(step, loss, val_loss)\n",
    "        # add acc\n",
    "        acc = kwargs.pop(\"acc\", None)\n",
    "        val_acc = kwargs.pop(\"val_acc\", None)\n",
    "        if acc is not None and val_acc is not None:\n",
    "            self.add_acc_scalars(step, acc, val_acc)\n",
    "        # add lr\n",
    "        learning_rate = kwargs.pop(\"lr\", None)\n",
    "        if learning_rate is not None:\n",
    "            self.add_lr_scalars(step, learning_rate)\n"
   ],
   "outputs": [],
   "execution_count": 6
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:26:18.129715Z",
     "start_time": "2025-01-26T07:26:18.125430Z"
    }
   },
   "source": [
    "class SaveCheckpointsCallback:\n",
    "    def __init__(self, save_dir, save_step=5000, save_best_only=True):\n",
    "        \"\"\"\n",
    "        Save checkpoints each save_epoch epoch. \n",
    "        We save checkpoint by epoch in this implementation.\n",
    "        Usually, training scripts with pytorch evaluating model and save checkpoint by step.\n",
    "\n",
    "        Args:\n",
    "            save_dir (str): dir to save checkpoint\n",
    "            save_epoch (int, optional): the frequency to save checkpoint. Defaults to 1.\n",
    "            save_best_only (bool, optional): If True, only save the best model or save each model at every epoch.\n",
    "        \"\"\"\n",
    "        self.save_dir = save_dir\n",
    "        self.save_step = save_step\n",
    "        self.save_best_only = save_best_only\n",
    "        self.best_metrics = -1\n",
    "        \n",
    "        # mkdir\n",
    "        if not os.path.exists(self.save_dir):\n",
    "            os.makedirs(self.save_dir) #makedirs 创建多层目录\n",
    "        \n",
    "    def __call__(self, step, state_dict, metric=None):\n",
    "        if step % self.save_step > 0:\n",
    "            return\n",
    "        \n",
    "        if self.save_best_only:\n",
    "            assert metric is not None\n",
    "            if metric >= self.best_metrics:\n",
    "                # save checkpoints\n",
    "                torch.save(state_dict, os.path.join(self.save_dir, \"best.ckpt\"))\n",
    "                # update best metrics\n",
    "                self.best_metrics = metric\n",
    "        else:\n",
    "            torch.save(state_dict, os.path.join(self.save_dir, f\"{step}.ckpt\"))\n",
    "\n"
   ],
   "outputs": [],
   "execution_count": 7
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:26:18.139822Z",
     "start_time": "2025-01-26T07:26:18.129715Z"
    }
   },
   "source": [
    "class EarlyStopCallback:\n",
    "    def __init__(self, patience=5, min_delta=0.01):\n",
    "        \"\"\"\n",
    "\n",
    "        Args:\n",
    "            patience (int, optional): Number of epochs with no improvement after which training will be stopped.. Defaults to 5.\n",
    "            min_delta (float, optional): Minimum change in the monitored quantity to qualify as an improvement, i.e. an absolute \n",
    "                change of less than min_delta, will count as no improvement. Defaults to 0.01.\n",
    "        \"\"\"\n",
    "        self.patience = patience\n",
    "        self.min_delta = min_delta\n",
    "        self.best_metric = -1\n",
    "        self.counter = 0\n",
    "        \n",
    "    def __call__(self, metric):\n",
    "        if metric >= self.best_metric + self.min_delta:\n",
    "            # update best metric\n",
    "            self.best_metric = metric\n",
    "            # reset counter \n",
    "            self.counter = 0\n",
    "        else: \n",
    "            self.counter += 1\n",
    "            \n",
    "    @property\n",
    "    def early_stop(self):\n",
    "        return self.counter >= self.patience\n"
   ],
   "outputs": [],
   "execution_count": 8
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:26:18.153813Z",
     "start_time": "2025-01-26T07:26:18.140813Z"
    }
   },
   "source": [
    "# 训练\n",
    "def training(\n",
    "    model, \n",
    "    train_loader, \n",
    "    val_loader, \n",
    "    epoch, \n",
    "    loss_fct, \n",
    "    optimizer, \n",
    "    tensorboard_callback=None,\n",
    "    save_ckpt_callback=None,\n",
    "    early_stop_callback=None,\n",
    "    eval_step=500,\n",
    "    ):\n",
    "    record_dict = {\n",
    "        \"train\": [],\n",
    "        \"val\": []\n",
    "    }\n",
    "    \n",
    "    global_step = 0\n",
    "    model.train()\n",
    "    with tqdm(total=epoch * len(train_loader)) as pbar:\n",
    "        for epoch_id in range(epoch):\n",
    "            # training\n",
    "            for datas, labels in train_loader:\n",
    "                datas = datas.to(device)\n",
    "                labels = labels.to(device)\n",
    "                # 梯度清空\n",
    "                optimizer.zero_grad()\n",
    "                # 模型前向计算\n",
    "                logits = model(datas)\n",
    "                # 计算损失\n",
    "                loss = loss_fct(logits, labels)\n",
    "                # 梯度回传\n",
    "                loss.backward()\n",
    "                # 调整优化器，包括学习率的变动等\n",
    "                optimizer.step()\n",
    "                preds = logits.argmax(axis=-1)\n",
    "            \n",
    "                acc = accuracy_score(labels.cpu().numpy(), preds.cpu().numpy())    \n",
    "                loss = loss.cpu().item()\n",
    "                # record\n",
    "                \n",
    "                record_dict[\"train\"].append({\n",
    "                    \"loss\": loss, \"acc\": acc, \"step\": global_step\n",
    "                })\n",
    "                \n",
    "                # evaluating\n",
    "                if global_step % eval_step == 0:\n",
    "                    model.eval()\n",
    "                    val_loss, val_acc = evaluating(model, val_loader, loss_fct)\n",
    "                    record_dict[\"val\"].append({\n",
    "                        \"loss\": val_loss, \"acc\": val_acc, \"step\": global_step\n",
    "                    })\n",
    "                    model.train()\n",
    "                    \n",
    "                    # 1. 使用 tensorboard 可视化\n",
    "                    if tensorboard_callback is not None:\n",
    "                        tensorboard_callback(\n",
    "                            global_step, \n",
    "                            loss=loss, val_loss=val_loss,\n",
    "                            acc=acc, val_acc=val_acc,\n",
    "                            lr=optimizer.param_groups[0][\"lr\"],\n",
    "                            )\n",
    "                    \n",
    "                    # 2. 保存模型权重 save model checkpoint\n",
    "                    if save_ckpt_callback is not None:\n",
    "                        save_ckpt_callback(global_step, model.state_dict(), metric=val_acc)\n",
    "\n",
    "                    # 3. 早停 Early Stop\n",
    "                    if early_stop_callback is not None:\n",
    "                        early_stop_callback(val_acc)\n",
    "                        if early_stop_callback.early_stop:\n",
    "                            print(f\"Early stop at epoch {epoch_id} / global_step {global_step}\")\n",
    "                            return record_dict\n",
    "                    \n",
    "                # udate step\n",
    "                global_step += 1\n",
    "                pbar.update(1)\n",
    "                pbar.set_postfix({\"epoch\": epoch_id})\n",
    "        \n",
    "    return record_dict\n",
    "        \n",
    "\n",
    "epoch = 100\n",
    "\n",
    "# 别 20 层了 2333，太深了没法训练\n",
    "model = NeuralNetwork(layers_num=10)\n",
    "\n",
    "# 1. 定义损失函数 采用交叉熵损失\n"
   ],
   "outputs": [],
   "execution_count": 9
  },
  {
   "cell_type": "code",
   "source": [
    "loss_fct = nn.CrossEntropyLoss()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-01-26T07:26:18.159394Z",
     "start_time": "2025-01-26T07:26:18.153813Z"
    }
   },
   "outputs": [],
   "execution_count": 10
  },
  {
   "cell_type": "code",
   "source": [
    "\n",
    "# 2. 定义优化器 采用SGD\n",
    "# Optimizers specified in the torch.optim package\n",
    "optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n",
    "\n",
    "# 1. tensorboard 可视化\n",
    "tensorboard_callback = TensorBoardCallback(\"runs/bn\")\n",
    "tensorboard_callback.draw_model(model, [1, 28, 28])\n",
    "# 2. save best\n",
    "save_ckpt_callback = SaveCheckpointsCallback(\"checkpoints/bn\", save_best_only=True)\n",
    "# 3. early stop\n",
    "early_stop_callback = EarlyStopCallback(patience=10, min_delta=0.001)\n",
    "\n",
    "model = model.to(device)\n",
    "record = training(\n",
    "    model,\n",
    "    train_loader,\n",
    "    val_loader,\n",
    "    epoch,\n",
    "    loss_fct,\n",
    "    optimizer,\n",
    "    tensorboard_callback=tensorboard_callback,\n",
    "    save_ckpt_callback=save_ckpt_callback,\n",
    "    early_stop_callback=early_stop_callback,\n",
    "    eval_step=len(train_loader)\n",
    "    )"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2025-01-26T07:42:25.346537Z",
     "start_time": "2025-01-26T07:26:18.160375Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "  0%|          | 0/375000 [00:00<?, ?it/s]"
      ],
      "application/vnd.jupyter.widget-view+json": {
       "version_major": 2,
       "version_minor": 0,
       "model_id": "a7ae99a7c4684df2a64e3fd7c3603e38"
      }
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Early stop at epoch 34 / global_step 127500\n"
     ]
    }
   ],
   "execution_count": 11
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:42:25.661386Z",
     "start_time": "2025-01-26T07:42:25.347037Z"
    }
   },
   "source": [
    "#画线要注意的是损失是不一定在零到1之间的\n",
    "def plot_learning_curves(record_dict, sample_step=500):\n",
    "    # build DataFrame\n",
    "    train_df = pd.DataFrame(record_dict[\"train\"]).set_index(\"step\").iloc[::sample_step]\n",
    "    val_df = pd.DataFrame(record_dict[\"val\"]).set_index(\"step\")\n",
    "\n",
    "    # plot\n",
    "    fig_num = len(train_df.columns)\n",
    "    fig, axs = plt.subplots(1, fig_num, figsize=(6 * fig_num, 5))\n",
    "    for idx, item in enumerate(train_df.columns):    \n",
    "        axs[idx].plot(train_df.index, train_df[item], label=f\"train_{item}\")\n",
    "        axs[idx].plot(val_df.index, val_df[item], label=f\"val_{item}\")\n",
    "        axs[idx].grid()\n",
    "        axs[idx].legend()\n",
    "        axs[idx].set_xlabel(\"step\")\n",
    "    \n",
    "    plt.show()\n",
    "\n",
    "plot_learning_curves(record, sample_step=10000)  #横坐标是 steps"
   ],
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1200x500 with 2 Axes>"
      ],
      "image/png": "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"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "execution_count": 12
  },
  {
   "cell_type": "code",
   "metadata": {
    "ExecuteTime": {
     "end_time": "2025-01-26T07:45:03.522244Z",
     "start_time": "2025-01-26T07:45:02.349051Z"
    }
   },
   "source": [
    "# dataload for evaluating\n",
    "model=model.to(device)\n",
    "# load checkpoints\n",
    "model.load_state_dict(torch.load(\"checkpoints/bn/best.ckpt\", weights_only=False, map_location=\"cpu\"))\n",
    "\n",
    "model.eval()\n",
    "loss, acc = evaluating(model, val_loader, loss_fct)\n",
    "print(f\"loss:     {loss:.4f}\\naccuracy: {acc:.4f}\")"
   ],
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "loss:     0.3192\n",
      "accuracy: 0.8884\n"
     ]
    }
   ],
   "execution_count": 14
  },
  {
   "metadata": {},
   "cell_type": "code",
   "outputs": [],
   "execution_count": null,
   "source": ""
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
